package Main;
import Grafos.*;
import Implementaciones.Floyd;
import Simulacion.*;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Clase que maneja la interacción entre el usuario y el programa, es aquí donde
 * se implementa todo lo necesario para crear los grafos y aplicar el algoritmo
 * de Floy.
 * @author Jonathan L.
 * @author Juan Argueta
 */
public class PlantearOpcion {
    /**
     * graphSize: tamaño del grafo.
     */
    public int graphSize;
    /**
     * opIn: 
     */
    protected int opIn;
    private ArrayList<String> nombreGrafo=new ArrayList<String>();
    
    Dialogos dialogos = new Dialogos();
    IngresoDatos ingreso = new IngresoDatos();
    ArrayList<ComponenteRed> vertices = new ArrayList<ComponenteRed>();
    ArrayList<Graph> listaGraphTemp = new ArrayList<Graph>();
    ArrayList<Graph> listaGraph = new ArrayList<Graph>();
    Graph<ComponenteRed, Double> grafoCase2 = new GraphMatrixUndirected<ComponenteRed, Double>(100);
    
    
    
    /**
     * Procedimiento para controlar todo lo relacionado con autogenerar una red.
     * Es una secuencia lineal que pide al usuario los datos necesarios para 
     * generar la red. También realiza la conexión de los componentes automáticamente.
     */
    public void case1(){
        dialogos.opcion1Intro();
        // Ingreso del tipo de red que desea crear.
        do{
            ingreso.ingresarNombreG();
            nombreGrafo.add(ingreso.getNombreRed());
            dialogos.opcionTipoRed();
            ingreso.ingresoGeneral(0, 2);
            ingreso.setIngresoC(ingreso.getUnica());
            ingreso.setTipoE(ingreso.getUnica());
        }while(ingreso.getUnica()==0);
        
        // Ingreso de la cantidad de computadoras que agrega a la red.
        do{
            ingreso.ingresarCantComputadoras();     
        }while(ingreso.getUnica()==0);
        
        //Ingreso de la cantidad de desktops de la red.
        do{
            ingreso.ingresarTipoDesktop();     
        }while(ingreso.getUnica()==-1);
        //Ingreso de la cantidad de laptops de la red.
        do{
            ingreso.ingresarTipoLaptop();     
        }while(ingreso.getUnica()==-1);
        
        // Preferencia por óptimo desempeño o velocidad
        do{
            dialogos.opcionEcono();
            ingreso.ingresoGeneral(0, 2);     
            ingreso.setcEcono(ingreso.getUnica());
        }while(ingreso.getcEcono()==0);
        
        // Inicia la creación de las redes para los casos indicados anteriormente.
        int cCompus = ingreso.getTipoDesk()+ingreso.getTipoLap();
        if(ingreso.getIngresoC()==1){
            Router router = new Router();
            for(Integer i=0; i<cCompus; i++){
                ComponenteRed compu = new Computadora();
                compu.setNombreComponente("computadora"+(i+1));
                vertices.add(compu);
            }                
            if (ingreso.getcEcono()==1){
                router.setNombreComponente("Router");
                router.setPrecio(ingreso.getcEcono());
                vertices.add(router);
            }else{
                router.setNombreComponente("Router");
                router.setPrecio(ingreso.getcEcono());
                vertices.add(router);    
            }
            
        }else if(ingreso.getIngresoC()==2){
            Router router = new Router();
            SwitchC switchC = new SwitchC();
            for(Integer i=0; i<cCompus; i++){
                ComponenteRed compu = new Computadora();
                compu.setNombreComponente("computadora"+(i+1));
                vertices.add(compu);
            }
            if (ingreso.getcEcono()==1){
                router.setNombreComponente("Router");
                router.setPrecio(ingreso.getcEcono());
                switchC.setNombreComponente("Switch1");
                switchC.setPrecio(1);
                vertices.add(router);
                vertices.add(switchC);
            }else{
                router.setNombreComponente("Router");
                router.setPrecio(ingreso.getcEcono());
                switchC.setPrecio(2);
                vertices.add(router);
                vertices.add(switchC);
            }
            
        }else if(ingreso.getIngresoC()==3){
            Router router = new Router();
            SwitchG switchG = new SwitchG();
            for(Integer i=0; i<cCompus; i++){
                ComponenteRed compu = new Computadora();
                compu.setNombreComponente("computadora"+(i+1));
                vertices.add(compu);
            }
            router.setNombreComponente("Router");
            switchG.setNombreComponente("Switch");
            switchG.setPrecio(2);
            router.setPrecio(2);
            vertices.add(router);
            vertices.add(switchG);
        }else if(ingreso.getIngresoC()==4){
            Router router = new Router();
            SwitchG switchG = new SwitchG();
            for(Integer i=0; i<=cCompus; i++){
                ComponenteRed compu = new Computadora();
                compu.setNombreComponente("computadora"+(i+1));
                vertices.add(compu);
            }
            router.setNombreComponente("Router");
            router.setPrecio(2);
            switchG.setNombreComponente("Switch");
            switchG.setPrecio(3);
            vertices.add(router);
            vertices.add(switchG);
        }
        for(int i=0; i<vertices.size(); i++){
            ComponenteRed vertice = vertices.get(i);
            System.out.println(vertices.get(i));
        }
        // Se agregan los vértices al grafo.
        Graph<ComponenteRed, Double> grafoCase1 = new GraphMatrixUndirected<ComponenteRed, Double>(vertices.size());
        for(int i=0;i<vertices.size();i++){
            grafoCase1.add(vertices.get(i));
        }
        if(ingreso.getIngresoC()==1){
            String utp = "UTP";
            Double vel = 0.01;
            Cable cable = new Cable(utp, vel);
            for (int i=0; i<vertices.size()-1;i++){
                grafoCase1.addEdge(vertices.get(vertices.size()-1), vertices.get(i), vel);
            }
        }else if (ingreso.getIngresoC()==2){
            String utp = "UTP";
            Double vel = 0.01;
            Cable cable = new Cable(utp, vel);
            for (int i=0; i<ingreso.getTipoDesk();i++){
                grafoCase1.addEdge(vertices.get(vertices.size()-1), vertices.get(i), vel);
            }
        }
        // Se aplica el algoritmo de Floyd para encontrar los caminos más cortos y los nodos
        // sin conexión.
        Floyd<ComponenteRed, Double> floyd = new Floyd<ComponenteRed, Double>(grafoCase1);
        grafoCase1 = floyd.getGraphD();
        System.out.println(grafoCase1.toString());
        listaGraph.add(grafoCase1);
        vertices.clear();
    }
    
    /**
     * Procedimiento que controla el ingreso de datos para que el usuario disponga de los
     * componentes para generar una red.
     */
    public void case2(){
        ingreso.ingresarNombreG();
        nombreGrafo.add(ingreso.getNombreRed());
        do{
            dialogos.desplegarMenu2();
            ingreso.ingresarInt(0,5);
            // Se llama al submenú que controla la interacción con el usuario.
            subMenuCase2(ingreso.getA());
        }while(ingreso.getA()!=5);
        vertices.clear();
    }
    
    private void subMenuCase2(int a){
        
        switch( a){
            case 1:
                // Ingreso de una computadora con el nombre del equipo.
                do{         
                    ingreso.ingresarComputadora();
                    Computadora computadora = new Computadora();
                    if(ingreso.getNombreE()!="0"){
                    computadora.setNombreComponente(ingreso.getNombreE());
                    vertices.add(computadora);
                    }else break;
                }while(ingreso.getUnica()==-1);               
                System.out.println(vertices.toString());
                
                break;
            case 2:
                // Ingreso de un componente de red.
                do{
                    ingreso.ingresarComRedM();
                    // Procedimiento para crear el componente de red.
                    componenteRed();
                    System.out.println(vertices.toString());
                }while(ingreso.getUnica()!=10);
                break;
            case 3:
                // Genera una conexión entre los vértices ingresados anteriormente.
                for(int i=0;i<vertices.size();i++){
                    System.out.println((i+1)+".  "+vertices.get(i).nombreComponente);
                }
                // Procedimiento para controlar las conexiones.
                case2Conexion();
                
                break;
            case 4:
                //Procedimiento para eliminar una conexión.
                case2ElimConexion();
                break;
            case 5:
                // Se aplica el algoritmo de Floyd para encontrar los caminos más cortos y los nodos
                // sin conexión.
                Floyd<ComponenteRed, Double> floyd = new Floyd<ComponenteRed, Double>(grafoCase2);
                grafoCase2 = floyd.getGraphD();
                listaGraph.add(grafoCase2);
                break;
        }
    }
    
    /*
     * Procedimiento para crear un componente de red con todas las características
     * necesarias para identificarlo correctamente.
     */
    private void componenteRed(){
        
        switch(ingreso.comRed){
            case 1:
                SwitchC switchC = new SwitchC("Linksys SE2500", null, null, null, 
                        "IEEE 802.3, 802.3u, 802.3x, 802.3ab", "5", 1000, null);
                vertices.add(switchC);
                break;
            case 2:
                SwitchC switchC1 = new SwitchC("Linksys SE2800", null, null, null, 
                        "IEEE 802.3, 802.3u, 802.3x, 802.3ab", "8", 1000, null);
                vertices.add(switchC1);
                break;
            case 3:
                SwitchG switchG = new SwitchG("Web Smart Switch TL-SL2218WEB TP-LINK",
                        null, null, null, "IEEE 802.3, 802.3u, 802.3ab, 802.3z, 802.3x, 802.1q, 802.1p", 
                        "26", 1000, null, 1);
                vertices.add(switchG);
                break;
            case 4:
                SwitchG switchG1 = new SwitchG("Web Smart Switch TL-SL2428WEB",
                        null, null, null, "IEEE 802.3, 802.3u, 802.3ab, 802.3z, 802.3x, 802.1q, 802.1p", 
                        "24", 1000, null, 2);
                vertices.add(switchG1);
                break;
            case 5:
                SwitchG switchG2 = new SwitchG("Web Smart Switch TL-SL2458WEB",
                        null, null, null, "IEEE 802.3, 802.3u, 802.3ab, 802.3z, 802.3x, 802.1q, 802.1p", 
                        "48", 1000, null, 2);
                vertices.add(switchG2);
                break;
            case 6:
                Router router = new Router("Linksys WRT160NL", null, "Wifi", 300, 
                        "802.3, 802.3u, 802.11b, 802.11g, 802.11n", "4", 100, 2.4, "N", 2);
                vertices.add(router);
                break;
            case 7:
                AccessPoint accessP = new AccessPoint("Aironet 3600", null, null, 300, "IEEE 802.11b, IEEE 802.11g, IEEE 802.11n, IEEE802.11b, IEEE802.11g, IEEE802.11n", 
                        null, null, 5.0, 4);
                vertices.add(accessP);
                break;
            case 8:
                Modem modem = new Modem("Motorola SurfBoard SB6141 DOCSIS 3.0", null, null, null, null, "1", 
                        100, null);
                vertices.add(modem);
                break;
            case 9:
                Impresora impresora = new Impresora("Impresora",null,null,null,null,null,100,null);
                
                vertices.add(impresora);
                break;
            case 10:
                
                break;
        }
    }
    
    /*
     * Procedimiento para generar una conexión entre vértices ya existentes.
     */
    private void case2Conexion(){
        for(int i=0;i<vertices.size();i++){
            grafoCase2.add(vertices.get(i));        
        }
        do{
            dialogos.agregarCConexion();
            ingreso.ingresoGeneral(0,2);   
        }while(ingreso.getUnica()==0);
        
        switch(ingreso.getUnica()){
            case 1:
                do{
                    ingreso.ingresarEquiposC(vertices.size());
                }while(ingreso.cCon1==-1||ingreso.cCon==-1);
                grafoCase2.addEdge(vertices.get(ingreso.cCon-1), vertices.get(ingreso.cCon1-1), 0.01);
                break;
            case 2:
                do{
                    ingreso.ingresarEquiposC(vertices.size());
                }while(ingreso.cCon1==-1||ingreso.cCon==-1);
                grafoCase2.addEdge(vertices.get(ingreso.cCon-1), vertices.get(ingreso.cCon1-1), 0.01);
        }
                
                
                System.out.println(grafoCase2.toString());
    }
    
    /*
     * Procedimiento para eliminar una conexión.
     */
    private void case2ElimConexion(){
        ingreso.ingresarEConexion(vertices.size());
        grafoCase2.removeEdge(vertices.get(ingreso.eCon1), vertices.get(ingreso.eCon2));
    }
    
    /**
     * Procedimiento para determinar la velocidad de conexión entre los dispositivos
     * que el usuario indicó.
     */
    public void case3(){
        
        
        
        int cont = 1;
        //dialogos.velocidadTT();
        for (int x=0; x<vertices.size(); x++){
            if (vertices.get(x).iscompu){
                System.out.println(cont + ". " + vertices.get(x).getNombreComponente());
                cont++;
            }  
        }
        int op = ingreso.ingresarVelT(listaGraph, nombreGrafo);
        Simulator<ComponenteRed, Double> s = new Simulator<ComponenteRed, Double>();
        if (op==2){
            double tiempo;
            tiempo = s.getTiempoTransferencia(ingreso.getGrafo(),ingreso.getEquipo1(), ingreso.getEquipo2(), ingreso.getPeso());
            if (tiempo==0){
                System.out.println("No existe conexión entre ambos equipos, no existe un tiempo de transferencia.");
            } else {
                System.out.println("El Tiempo de Transferencia para un Archivo de " + ingreso.getPeso() + "MB entre " + ingreso.getEquipo1() + " y " + ingreso.getEquipo2() + "es de: " + tiempo + "segundos.");
            }
        } else {
            double[] est;
            est = s.getEstadistica(ingreso.getGrafo(), ingreso.getPeso(), ingreso.getEquipo1());
            if((est[0]==0)&&(est[1]==0)&&(est[2]==0)){
                System.out.println("La Red se Encuentra Vacía, no se Pueden Realizar Estadísticas de Velocidad de Transferencia");
            } else {
                System.out.println("\nLa Velocidad Mínima de Transferencia es: " + est[0] + "Mbps.");
                System.out.println("\nLa Velocidad Máxima de Transferencia es: " + est[1] + "Mbps.");
                System.out.println("\nLa Velocidad Promedio de Transferencia es: " + est[2] + "Mbps.");
            }  
        }   
    }
    
    /**
     * Procedimiento para salir del programa.
     */
    public void case4(){
        dialogos.salir();
    }
}
